package cn.bbstone.pisces2.client.handler;

import cn.bbstone.pisces2.client.base.ClientCache;
import cn.bbstone.pisces2.client.task.impl.FileTask;
import cn.bbstone.pisces2.client.util.MsgUtil;
import cn.bbstone.pisces2.comm.BFileCmd;
import cn.bbstone.pisces2.comm.StatusEnum;
import cn.bbstone.pisces2.comm.cache.ClientFliIndexCache;
import cn.bbstone.pisces2.proto.rsp.RspFile;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RspListDataHandler implements ClientHandler {
    private static Logger log = LoggerFactory.getLogger(RspListDataHandler.class);

    public RspListDataHandler() {
    }

    @Override
    public void handle(ChannelHandlerContext ctx, RspFile rspFile) {
        String msgId = rspFile.getMsgId();
        Byte msgType = rspFile.getMsgType();
        long fileNo = rspFile.getFileNo();
        log.debug("msg id: {}, msgType: {}, fileNo: {}, bodyLen: {}, bodyData.len: {}",
                msgId, msgType, fileNo, rspFile.getBodyLen(), rspFile.getBodyData().length);
        //
        FileTask fileTask = ClientCache.getTask(fileNo);
        if (fileTask == null) {
            throw new RuntimeException(String.format("not found FileTask for fileNo: %d", fileNo));
        }
        // save file data
        StatusEnum status = fileTask.appendFileData(rspFile);
//        StatusEnum status = fileTask.appendFileData(rspFile.getBodyData());
        if (status == StatusEnum.COMPLETED || status == StatusEnum.CONTINUE) {
            log.debug("+++++ file(fileNo: {}, rpath: {}, chunkNo: {}) transfer complete. ", fileNo, ClientFliIndexCache.getClientIndexNotUpdatePos(fileNo).getRpath(), rspFile.getChunkNo());
            // send ack  when one chunk recv completed, send FILE_DATA_ACK REQ to server,
            // if server rec this ack, will continue chunk data dilivery
            sendReqListDataAck(ctx, rspFile.getFileNo());
            log.info("receive total progress: {}/{}, index progress: {}/{}, index fileSize: {} B.",
                    rspFile.getFileNo(), ClientCache.getSpCount(), rspFile.getChunkNo(), fileTask.chunks(), fileTask.fileSize());
            //
            if (status == StatusEnum.COMPLETED) {
                log.debug("====== file (fileNo: {}, rpath: {}) transfer complete. ======", fileNo, ClientFliIndexCache.getClientIndexNotUpdatePos(fileNo).getRpath());
                //
                MsgUtil.rspListDataCompleted();
                // do request first line(file-rpath) in fli.idx if fileCat = F
                handleNext(ctx, rspFile, fileTask);
            }
        } else { // .fli.idx
            log.error("recv indexdata chunk error, status.code: {}, status.msg: {}", status.code(), status.descp());
            // TODO handle client recv index data error...
            // already handle in TaskListener.onFail(FailEvent) method
        }
    }

    /**
     * do request first line(file-rpath) in fli.idx if fileCat = F
     *
     * @param ctx
     */
    @Override
    public void handleNext(ChannelHandlerContext ctx, RspFile rspFile, FileTask fileTask) {
        MsgUtil.reqNextFileInfo(ctx);
        /*
        FliSavePoint fliSavePoint = FLIUtil.readClientSavePoint();
        if (fliSavePoint.getFileNo() > 0) { // start from fileNo = 1
            log.debug("-->-->--> start req file from save-point, fileNo: {}", fliSavePoint.getFileNo());
            MsgUtil.reqNextFileInfo(ctx, fliSavePoint.getFileNo());
//            for (int i = 0; i < (Config.taskNum() - 1); i++) {
//                TaskExecutor taskExecutor = new TaskExecutor(ctx);
//                TaskExecutorPool.submit(taskExecutor);
//            }
        } else { // start from fileNo = sp.fileNo
//            for (int i = 0; i < Config.taskNum(); i++) {
//                TaskExecutor taskExecutor = new TaskExecutor(ctx);
//                TaskExecutorPool.submit(taskExecutor);
//            }
            MsgUtil.reqNextFileInfo(ctx);
        }*/
    }

    private void sendReqListDataAck(ChannelHandlerContext ctx, long fileNo) {
        //        log.info("(fileNo: {}) Ack FILE DATA Chunk recv complete.", rspFile.getFileNo());
        ByteBuf out = MsgUtil.buildReq(BFileCmd.REQ_LIST_DATA_ACK, fileNo);
        ctx.writeAndFlush(out);
    }

}
